package com.ctvit.breadking.news.core.solr.config;

import com.ctvit.breadking.news.core.constant.CommonConstant;
import com.ctvit.breadking.news.core.solr.config.properties.SolrProperties;
import com.ctvit.breadking.news.core.solr.interceptor.PreemptiveAuthInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.apache.solr.client.solrj.impl.LBHttpSolrClient;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.stream.Stream;

/**
 * Solr配置类
 *
 * @author heyingcheng
 * @date 2024/10/2
 */
@Slf4j
@EnableConfigurationProperties(SolrProperties.class)
@Configuration
public class SolrConfig {

    private final String username;

    private final String password;

    private final int connTimeout;

    private final int socketTimeout;

    private final String shardsUri;

    private final String[] baseUrls;

    private final int urlLength;

    private final Map<String, String> baseUrlMap;

    public SolrConfig(SolrProperties solrProperties) throws MalformedURLException {
        this.username = solrProperties.getUsername();
        this.password = solrProperties.getPassword();
        this.connTimeout = solrProperties.getConnTimeout();
        this.socketTimeout = solrProperties.getSocketTimeout();
        this.shardsUri = solrProperties.getShardsUri();
        this.baseUrls = solrProperties.getBaseUrls();
        this.urlLength = baseUrls.length;
        this.baseUrlMap = new LinkedHashMap<>(urlLength);
        for (String baseUrl : this.baseUrls) {
            baseUrlMap.put(new URL(baseUrl).getAuthority(), baseUrl);
        }
    }

    private CloseableHttpClient buildCloseableHttpClient() {
        CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));
        HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
        httpClientBuilder.addInterceptorFirst(new PreemptiveAuthInterceptor());
        httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
        return httpClientBuilder.build();
    }

    public LBHttpSolrClient buildLbHttpSolrClient() {
        return buildLbHttpSolrClient(baseUrls);
    }

    public LBHttpSolrClient buildLbHttpSolrClient(String collection) {
        String[] collectionUrls = Stream.of(baseUrls).map(baseUrl -> baseUrl + CommonConstant.LINUX_SEPARATOR + collection).toArray(String[]::new);
        return buildLbHttpSolrClient(collectionUrls);
    }

    public LBHttpSolrClient buildLbHttpSolrClient(String[] baseUrls) {
        LBHttpSolrClient.Builder lbBuilder = new LBHttpSolrClient.Builder();
        lbBuilder.withBaseSolrUrls(baseUrls);
        lbBuilder.withConnectionTimeout(connTimeout);
        lbBuilder.withSocketTimeout(socketTimeout);
        lbBuilder.withHttpClient(buildCloseableHttpClient());
        return lbBuilder.build();
    }

    public void buildHttpSolrClients(BiConsumer<String, HttpSolrClient> consumer) {
        Set<Map.Entry<String, String>> entries = baseUrlMap.entrySet();
        for (Map.Entry<String, String> entry : entries) {
            consumer.accept(entry.getKey(), new HttpSolrClient.Builder(entry.getValue()).withHttpClient(buildCloseableHttpClient()).build());
        }
    }

    public List<HttpSolrClient> buildHttpSolrClientList() {
        List<HttpSolrClient> httpSolrClientList = new ArrayList<>(urlLength);
        buildHttpSolrClients((authority, httpSolrClient) -> httpSolrClientList.add(httpSolrClient));
        return httpSolrClientList;
    }


    public Map<String, HttpSolrClient> buildHttpSolrClientMap() {
        Map<String, HttpSolrClient> httpSolrClientMap = new LinkedHashMap<>(urlLength);
        buildHttpSolrClients(httpSolrClientMap::put);
        return httpSolrClientMap;
    }

    public String getShardsUri(String collection) {
        return this.shardsUri + CommonConstant.LINUX_SEPARATOR + collection;
    }

}
